#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>

#include "utils_fifo.h"
#include "hal_tty.h"

#include "hk32c030xx_conf.h"

#include "FreeRTOS.h"
#include "portable.h"
#include "semphr.h"

static ring_buffer_t *ringbuf_send, *ringbuf_recv;/*收发缓冲区管理 ---------*/

static uint8_t dma_tx_buf[TTY_TXBUFFER_SIZE];/*DMA发送缓冲区 ---------*/
static uint8_t dma_rx_buf[TTY_RXBUFFER_SIZE];/*DMA接收缓冲区 ---------*/      
static SemaphoreHandle_t tty_semap_;

static void tty_gpio_init() {
	
	GPIO_InitTypeDef uart_io_struct;
	RCC_AHBPeriphClockCmd(TTY_UART_IO_RCU, ENABLE);
			
    GPIO_PinAFConfig(TTY_UART_IO_BASE, TTY_TX_PIN_SOURCE, GPIO_AF_1);
    GPIO_PinAFConfig(TTY_UART_IO_BASE, TTY_RX_PIN_SOURCE, GPIO_AF_1);
	
	uart_io_struct.GPIO_Mode = GPIO_Mode_AF;
	uart_io_struct.GPIO_Pin = TTY_UART_TX_PIN | TTY_UART_RX_PIN;
    uart_io_struct.GPIO_OType = GPIO_OType_PP;
    uart_io_struct.GPIO_Speed = GPIO_Speed_50MHz;
    uart_io_struct.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(TTY_UART_IO_BASE, &uart_io_struct);
}

static void tty_uart_init() {

	UART_InitTypeDef tty_struct;
	NVIC_InitTypeDef tty_nvic;

	RCC_APB2PeriphClockCmd(TTY_UART_RCU,ENABLE);

	UART_StructInit(&tty_struct);
	tty_struct.UART_BaudRate = TTY_BAUDRATE;
	tty_struct.UART_WordLength = UART_WordLength_8b;
	tty_struct.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;
	tty_struct.UART_Parity = UART_Parity_No;
	tty_struct.UART_StopBits = UART_StopBits_1;
	
	tty_nvic.NVIC_IRQChannel = UART1_IRQn;
    tty_nvic.NVIC_IRQChannelPriority = 0;
    tty_nvic.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&tty_nvic);
	
	UART_Init(TTY_UART_CORE, &tty_struct);

	UART_DMACmd(TTY_UART_CORE,UART_DMAReq_Tx, ENABLE);
	UART_DMACmd(TTY_UART_CORE,UART_DMAReq_Rx, ENABLE);

	UART_ITConfig(TTY_UART_CORE, UART_IT_TC, DISABLE);     
	
	UART_ITConfig(TTY_UART_CORE, UART_IT_IDLE, ENABLE);
	//UART_ITConfig(TTY_UART_CORE, UART_IT_ERR, ENABLE);    
		
    ringbuf_send = ring_buffer_create(TTY_TXFIFO_SIZE);
    ringbuf_recv = ring_buffer_create(TTY_RXFIFO_SIZE);
}

static void tty_dma_init() {
		
	DMA_InitTypeDef dma_struct;	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA, ENABLE);  
	
#if DMA_UART_REMAP
	SYSCFG_DMAChannelRemapConfig(SYSCFG_DMARemap_UART1Rx,ENABLE);
	SYSCFG_DMAChannelRemapConfig(SYSCFG_DMARemap_UART1Tx,ENABLE);
#endif 
	DMA_DeInit(TTY_DMA_TX_CHANNEL);
    DMA_DeInit(TTY_DMA_RX_CHANNEL);
	
	dma_struct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    dma_struct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    dma_struct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    dma_struct.DMA_MemoryInc = DMA_MemoryInc_Enable;
    dma_struct.DMA_Mode = DMA_Mode_Normal;
    dma_struct.DMA_M2M = DMA_M2M_Disable;
	
	dma_struct.DMA_PeripheralBaseAddr = (uint32_t)(&TTY_UART_CORE->TDR);
	dma_struct.DMA_BufferSize = sizeof(dma_tx_buf);
	dma_struct.DMA_MemoryBaseAddr = (uint32_t)dma_tx_buf;
    dma_struct.DMA_DIR = DMA_DIR_PeripheralDST;  
	dma_struct.DMA_Priority = DMA_Priority_High;
    DMA_Init(TTY_DMA_TX_CHANNEL, &dma_struct);
	
	dma_struct.DMA_PeripheralBaseAddr = ((uint32_t)&TTY_UART_CORE->RDR);
	dma_struct.DMA_BufferSize = sizeof(dma_rx_buf);
    dma_struct.DMA_MemoryBaseAddr = (uint32_t)dma_rx_buf;
    dma_struct.DMA_DIR = DMA_DIR_PeripheralSRC;
    dma_struct.DMA_Priority = DMA_Priority_Low;
	dma_struct.DMA_Mode = DMA_Mode_Circular;
	DMA_Init(TTY_DMA_RX_CHANNEL, &dma_struct);
	
	DMA_ITConfig(TTY_DMA_RX_CHANNEL, DMA_IT_TC, ENABLE);    
	DMA_ITConfig(TTY_DMA_RX_CHANNEL, DMA_IT_HT, ENABLE);
	
	UART_Cmd(TTY_UART_CORE, ENABLE);
	DMA_Cmd(TTY_DMA_RX_CHANNEL,ENABLE); 

	NVIC_InitTypeDef dma_nvic;
	dma_nvic.NVIC_IRQChannel = DMA_Channel2_3_IRQn;
    dma_nvic.NVIC_IRQChannelPriority = 1;
    dma_nvic.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&dma_nvic);  
}

void UART1_IRQHandler(void) {

	if(UART_GetITStatus(TTY_UART_CORE,UART_IT_IDLE) != RESET) {
		UART_ClearITPendingBit(TTY_UART_CORE,UART_IT_IDLE);
	 
		uint16_t value = UART_ReceiveData(TTY_UART_CORE);		
		uint16_t remain_len = TTY_RXBUFFER_SIZE - (uint16_t)DMA_GetCurrDataCounter(TTY_DMA_RX_CHANNEL);
		DMA_Cmd(TTY_DMA_RX_CHANNEL,DISABLE);
		if(remain_len) {
			if(remain_len > TTY_HALF_RX_BUFFER_SIZE) {
				ring_buffer_put(ringbuf_recv,dma_rx_buf + TTY_HALF_RX_BUFFER_SIZE, remain_len - TTY_HALF_RX_BUFFER_SIZE);    /*将数据放入接收缓冲区*/ 
			} else {
				ring_buffer_put(ringbuf_recv,dma_rx_buf, remain_len);    /*将数据放入接收缓冲区*/ 
			}
			
			BaseType_t value;
			xSemaphoreGiveFromISR(tty_semap_,&value);
		} else {
		}
		
		// while (DMA_GetCmdStatus(TTY_DMA_RX_CHANNEL) != DISABLE && retry++ < 100){}  
		DMA_SetCurrDataCounter(TTY_DMA_RX_CHANNEL,TTY_RXBUFFER_SIZE);
		DMA_ClearFlag(DMA_FLAG_TC3);
        DMA_Cmd(TTY_DMA_RX_CHANNEL,ENABLE);
	}
		
	if(UART_GetITStatus(TTY_UART_CORE,UART_IT_TC) == SET) {
		//UART_ClearITPendingBit(TTY_UART_CORE,UART_IT_TC);
		int len = ring_buffer_get(ringbuf_send,dma_tx_buf,TTY_TXBUFFER_SIZE);
        if (len != 0) {
            DMA_Cmd(TTY_DMA_TX_CHANNEL,DISABLE);
			DMA_ClearFlag(DMA_FLAG_TC2);
            DMA_SetCurrDataCounter(TTY_DMA_TX_CHANNEL, len);
            DMA_Cmd(TTY_DMA_TX_CHANNEL, ENABLE);
			UART_ClearFlag(TTY_UART_CORE, UART_FLAG_TC);
        } else {
			UART_ITConfig(TTY_UART_CORE,UART_IT_TC, DISABLE);
        }
	}
}

void DMA_Channel2_3_IRQHandler() {
	uint8_t flag = 0;
	if(DMA_GetFlagStatus(DMA_FLAG_HT3) != RESET) {
		ring_buffer_put(ringbuf_recv, dma_rx_buf, TTY_HALF_RX_BUFFER_SIZE);
		DMA_ClearFlag(DMA_FLAG_HT3);
		flag = 1;
	}
	
	 if(DMA_GetFlagStatus(DMA_FLAG_TC3) != RESET) {
		ring_buffer_put(ringbuf_recv, dma_rx_buf + TTY_HALF_RX_BUFFER_SIZE, TTY_HALF_RX_BUFFER_SIZE);
		DMA_ClearFlag(DMA_FLAG_TC3);
		flag = 1;
	 }
	 
	 if(flag) {
	 	 BaseType_t value;
		xSemaphoreGiveFromISR(tty_semap_,&value);
	 }
}

static void tty_init() {

	tty_gpio_init();
	tty_uart_init();
	tty_dma_init();
	
	tty_semap_ = xSemaphoreCreateBinary();
}

static uint16_t tty_send(void *buf,uint16_t len) {
	
    int16_t send_len = 0;
    while(send_len < len) {
		send_len += ring_buffer_put(ringbuf_send, buf + send_len, len - send_len);
		UART_ITConfig(TTY_UART_CORE,UART_IT_TC,ENABLE);
    }
	UART_ClearFlag(TTY_UART_CORE,UART_FLAG_TC);

    return len;
}

static uint16_t tty_recv(void *buf, uint16_t len) {
	
	uint16_t data_size = ring_buffer_len(ringbuf_recv);
	if(data_size > 0) {
		return ring_buffer_get(ringbuf_recv, (unsigned char *)buf, len);
	} else {
		if(xSemaphoreTake(tty_semap_,pdMS_TO_TICKS(1000)) == pdTRUE) {
			return ring_buffer_get(ringbuf_recv, (unsigned char *)buf, len);
		}
	}
	
	return 0;
}

static void tty_putstr(const char *str) {
    tty_send((void *)str, strlen(str));
}

static void tty_clear(void) {
    ring_buffer_clr(ringbuf_recv);
}

static uint16_t tty_buflen(void) {
    return ring_buffer_len(ringbuf_recv);
}

static void tty_print(const char *format, ...) {
    va_list args;
    char buf[128] = {0};
    va_start(args, format);
    vsprintf(buf, format, args);       
    va_end(args);    
    tty_putstr(buf);
}

const tty_t g_tty_ = {
    tty_init,
    tty_send,
    tty_recv,
    tty_putstr,
    tty_clear,
    tty_buflen,
    tty_print
};

